package com.dm.cloud.images.service.impl;

import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSONObject;
import com.github.dockerjava.api.DockerClient;
import com.dm.cloud.core.exception.CustomException;
import com.dm.cloud.images.common.mode.ImageMode;
import com.dm.cloud.images.common.mode.ImageTag;
import com.dm.cloud.images.common.po.ImagesEndpoint;
import com.dm.cloud.images.mode.CommonProp;
import com.dm.cloud.images.mode.fileupload.ImageUploadMerge;
import com.dm.cloud.images.service.ImagesEndpointService;
import com.dm.cloud.images.util.DockerUtil;
import com.dm.cloud.images.util.LocalUtil;
import com.dm.cloud.images.util.RepositoryUtils;
import com.dm.cloud.images.service.RepositoryServerService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.util.Arrays;
import java.util.List;

@Service
@Slf4j
public class RepositoryServerServiceImpl implements RepositoryServerService {

    @Autowired
    private RepositoryUtils repositoryUtils;

    @Autowired
    private ImagesEndpointService imagesEndpointService;

    @Autowired
    private LocalUtil localUtil;

    private DockerClient defaultClient(){
        ImagesEndpoint endpoint=imagesEndpointService.findActiveLimit1();
        if(endpoint==null){
            throw new CustomException("没有可用的容器节点");
        }
        //获取连接
        return DockerUtil.get(endpoint.getHost(), endpoint.getDockerPort());
    }

    @Override
    public Object uploadImage(MultipartFile file) {
        DockerClient client = null;
        InputStream in=null;
        try {
            client = defaultClient();
            in = file.getInputStream();
            log.info("开始加载镜像:"+file.getOriginalFilename());
            String imageName = DockerUtil.loadImage(client, in);
            log.info("镜像加载到本地:"+imageName);
            log.info("开始推送镜像:"+imageName);
            String reportImageName=repositoryUtils.pushByLocal(client,imageName);
            log.info("推送镜像成功:"+reportImageName);
            //上传成功后删除本地镜像
            try {
                DockerUtil.deleteImage(client,imageName,false);
                DockerUtil.deleteImage(client,reportImageName,false);
            }catch (Exception e){
                e.printStackTrace();
            }
            return reportImageName;
        } catch (IOException e) {
            e.printStackTrace();
            throw new CustomException(e.getMessage());
        }finally {
            try {
                in.close();
            } catch (IOException e) {
//                e.printStackTrace();
            }
            try {
                client.close();
            }catch (Exception e){

            }
        }
    }

    @Override
    public List<ImageMode> searchImages(Integer page, Integer page_size, String sort, String q) {

        return repositoryUtils.searchImages(page,page_size,sort,q);
    }

    @Override
    public Boolean deleteImage(String imageName) {
        if(StrUtil.isEmpty(imageName)){
            throw new CustomException("要删除的镜像名称不能为空!");
        }
        repositoryUtils.deleteImage(imageName);
        return true;
    }

    @Override
    public List<ImageTag> imageTags(String imageName) {

        return repositoryUtils.imageTags(imageName);
    }

    @Override
    public Boolean deleteTag(String digest,String imageName, String tag) {
        if(StrUtil.isEmpty(digest)){
            throw new CustomException("digest标识不能为空！");
        }
        if(StrUtil.isEmpty(tag)){
            throw new CustomException("tag标识不能为空！");
        }
        if(StrUtil.isEmpty(imageName)){
            throw new CustomException("镜像标识不能为空！");
        }
        try {
            repositoryUtils.deleteTags(digest,imageName,tag);
        }catch (Exception e){
            e.printStackTrace();
            throw new CustomException("删除失败，tag不存在，请刷新重新操作");
        }
        return true;
    }

    @Override
    public String imageShardMerge(ImageUploadMerge fileUploadMerge) {
        if(StrUtil.isEmpty(fileUploadMerge.getFileKey())){
            throw new CustomException("fileKey不能为空！");
        }
        //本地分片目录
        File hashDir = localUtil.getShardWork(fileUploadMerge.getFileKey());
        ByteArrayInputStream input=null;
        if(!hashDir.exists() || !hashDir.isDirectory()){
            throw new CustomException("分片存储不存在");
        }
        DockerClient client = null;
        try {
            client = defaultClient();
            boolean next=true;
            byte[] allBytes=null;
            int shardIndex=0;
            while (next){
                String shardName= CommonProp.SHARD_FILE_PREFIX+shardIndex;
                File shardFile=new File(hashDir+File.separator+shardName);
                if(!shardFile.exists()){
                    next=false;
                    continue;
                }
                FileInputStream in = null;
                try {
                    in=new FileInputStream(shardFile);
                    byte[] shardByts = IoUtil.readBytes(in, true);
                    if(allBytes==null){
                        allBytes=shardByts;
                    }else{
                        int starIndex=allBytes.length;
                        byte[] ndata=Arrays.copyOf(allBytes,allBytes.length+shardByts.length);
                        for (int i = 0; i < shardByts.length; i++) {
                            ndata[starIndex+i]=shardByts[i];
                        }
                        allBytes=ndata;
                    }

                }catch (Exception e){
                    e.printStackTrace();
                    throw new CustomException("分片文件合并失败!");
                }finally {
                    try {
                        in.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                shardIndex++;
            }

            input = new ByteArrayInputStream(allBytes);
            String imageName = DockerUtil.loadImage(client, input);
            log.info("镜像加载到本地:"+imageName);
            log.info("开始推送镜像:"+imageName);
            String reportImageName=repositoryUtils.pushByLocal(client,imageName);
            log.info("推送镜像成功:"+reportImageName);
            //上传成功后删除本地镜像
            try {
                DockerUtil.deleteImage(client,imageName,false);
                DockerUtil.deleteImage(client,reportImageName,false);
            }catch (Exception e){
                e.printStackTrace();
            }
            return reportImageName;
        } catch (Exception e) {
            e.printStackTrace();
            throw new CustomException(e.getMessage());
        }finally {
            try {
                input.close();
            } catch (IOException e) {
            }
            try {
                client.close();
            }catch (Exception e){
            }
        }

    }

    @Override
    public JSONObject tagDetail(String imageName, String sha256Ids) {
        if(StrUtil.isEmpty(imageName)) throw new CustomException("名称不能为空!");
        if(StrUtil.isEmpty(sha256Ids)) throw new CustomException("sha256值不能为空!");
        return repositoryUtils.tagDetail(imageName,sha256Ids);
    }
}
